#include "directorios.h"
#include "ficheros_basico.h"
#include "lectores_escritores.h"

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int mutex;


int montar(const char *nombre_disco){

	//int res = bmount(nombre_disco);

	if(bmount(nombre_disco) == -1){
		printf("directorios.c -> montar => Error al montar \n");
		return -1;
	}
	else{
		mutex = nuevo_sem(ftok("/home/" , 's'), 1);
		inicializar_sem(mutex, 1);
	
		return 0;
	}

}

int desmontar(){

	bumount();

	eliminar_sem(mutex);

}

int extraer_camino(const char *camino, char *inicial, char *final){

	int i = 0;
	int j= 0;
	int tipo = 1;		//variable que vale 0 si es directorio y 1 si es fichero
	
	if (camino[i] != '/'){
		printf("directorios.c -> extraer_camino => Error camino vacio \n");
		return -1;
	} else {
		
		i++;
		//Obtenemos lo que hay en los dos primeros '/'
		while ((camino[i] != '/') && (camino[i] != '\0')){
			inicial[i-1] = camino[i];
			i++;
		}
		inicial[i] = '\0';
		
		//Obtenemos el final
		while (camino[i] != '\0'){
			final[j] = camino[i];
			i++; j++;
			tipo = 0;
		}
		final[j] = '\0';
	
	}
	printf("camino inicial: %s\n",inicial);
	printf("camino final: %s\n",final);
	return tipo;
	
}

int buscar_entrada(const char *camino_parcial, unsigned int *p_inodo_dir, unsigned int *p_inodo, unsigned int *p_entrada){

	inodo inod;
	entrada dir;
	memset(dir.nombre, '\0', sizeof(entrada));
	
	char cam_ini[100];
	memset(cam_ini, '\0', 80); 
	char cam_final[200];
	memset(cam_final, '\0', 200);

	int bytes_leidos = 0;
	int tipo_camino;
	tipo_camino = extraer_camino(camino_parcial, cam_ini, cam_final);

	int n = 0;
	
	//Miramos si el camino esta vacio
	if(tipo_camino == -1){
		printf("directorios.c -> buscar_entrada => Error, Camino vacio \n");

		return -1; 
	}
	
	//if((camino_parcial[0] == '/') || (strcmp(camino_parcial, "/") == 0)){
	if((strcmp(camino_parcial, "/") == 0)){
	//	*p_entrada = 0;
		*p_inodo = 0;
		*p_inodo_dir = 0;
		
		return 0;
	}

	inod = leer_inodo(*p_inodo_dir);

	//Buscamos el directorio
	while((bytes_leidos < inod.tamano) && (mi_read_f(*p_inodo_dir, &dir, bytes_leidos, sizeof(n))) && (strcmp(dir.nombre, cam_ini) != 0)){
		bytes_leidos = bytes_leidos + sizeof(n); 
		n = n + 1;
	}

	*p_inodo = *p_inodo_dir;
	*p_entrada = n;

	if(strcmp(dir.nombre, cam_ini) == 0){
		
		//Fichero
		if(tipo_camino == 1){
			*p_inodo = dir.inodo;
			*p_entrada = n;
		
			return 1;
		}
		
		//Directorio
		else if(strcmp(cam_final, "/") == 0){
			*p_inodo = dir.inodo;
			*p_entrada = n;

			return 0;

		}

		else{
			*p_inodo_dir = dir.inodo;

			return buscar_entrada(cam_final, p_inodo_dir, p_inodo, p_entrada);
		}
	}
	else{
		
		return -1;
	}	
}

int mi_creat(const char *camino){
/*
	esperar_sem(mutex, 0, 0);
	
	entrada entr;
	inodo inod;
	
	unsigned int p_inodo_dir, p_inodo, p_entrada;
	p_inodo_dir = 0;
	p_inodo = 0;
	p_entrada = 0;
	
	char cam_ini[100] = "\0";
	//memset(cam_ini, '\0', 100); 
	char cam_final[200] = "\0";
	//memset(cam_final, '\0', 200);
	char cam_aux[200];
	//memset(cam_aux, '\0', 200);
	
	//Creamos el directorio o fichero
	if(camino[strlen(camino) - 1] == '/'){
		inod.tipo = 1;
	}else{
		inod.tipo = 2;
	}
	
	
	printf("Camino: %s \n", camino);
	printf("Inodo tipo: %d\n", inod.tipo);
	
	strcpy(cam_aux, camino);
	int r = extraer_camino(cam_aux, cam_ini, cam_final);
	
	printf("Valor extraer camino: %d\n", r);
	
	while (strlen(cam_final) > 1) {
		printf("Dentro del bucle strlen\n");
		if(buscar_entrada(cam_ini, &p_inodo_dir, &p_inodo, &p_entrada) == -1){
			printf("directorios.c -> mi_creat => Error, no se puede crear %s porque no existe %s \n", camino, cam_ini);
			printf("\tInodo_dir: %d\tInodo: %d\tEntrada: %d\n\n", p_inodo_dir, p_inodo, p_entrada);
			senalizar_sem(mutex, 0); 
			return -1;
		}
		
		//printf("Valor buscar entrada: %d\n", buscar_entrada(cam_ini, &p_inodo_dir, &p_inodo, &p_entrada));
		
		p_inodo_dir = p_inodo;
		strcpy(cam_aux, cam_final);
		printf("valor cam_final: %s  -  cam_aux despues if $s \n", cam_final, cam_aux);
		extraer_camino(cam_aux, cam_ini,cam_final);
	}
	
	if(buscar_entrada(camino, &p_inodo_dir, &p_inodo, &p_entrada) == -1){
		printf("valor buscar entrada: %d \n", buscar_entrada(camino, &p_inodo_dir, &p_inodo, &p_entrada));
		printf("Creando '%s' !!! \n", camino);	

		entr.inodo = reservar_inodo(inod.tipo);
		strcpy(entr.nombre, cam_ini);
		inod = leer_inodo(p_inodo_dir);
		mi_write_f(p_inodo_dir, &entr, p_entrada * sizeof(entr), sizeof(entr));
		
	}
	
	senalizar_sem(mutex, 0); 

	return 0;
*/

	esperar_sem(mutex, 0, 0); 

	//int valor_devuelto;

	entrada ent;
	inodo in;

	unsigned int p_inodo_dir, p_inodo, p_entrada;

	char inicial[80]; memset(inicial, '\0', 80);
	char final[200]; memset(final, '\0', 200);
	char aux[200]; memset(aux, '\0', 200);

	int cont=0;
	int i=0;


	//Contamos cuantos '/' hay para luego ver si lo que hay antes de lo queremos crear, existe o no
	while(camino[i] != '\0'){
		if(camino[i] == '/'){
			cont++;
		}
	
		i++;
	}

	extraer_camino(camino, inicial, final);

	while((strcmp(final, "/") != 0) && (strcmp(final, "\0") != 0)){
		memset(inicial, '\0', 80);
		extraer_camino(final, inicial, final);
	}

	i=0;

	if(((final[0] == '/') && (final[1] != '\0')) || ((final[0] == '/') && (final[1] == '\0'))){
		cont--;
	}

	int j = cont;

	while(j != 0){
		if(camino[i] == '/'){
			j--;
		}

		aux[i] = camino[i];

		i++;
	}

	p_inodo_dir = p_inodo = p_entrada = 0;


	if(cont >= 2){	

		//Veremos si existe el directorio anterior. Si no existe no se puede crear lo que queremos
		if(buscar_entrada(aux, &p_inodo_dir, &p_inodo, &p_entrada) == -1){
			printf("ERROR! no se puede crear %s porque no existe %s \n", camino, aux);

			senalizar_sem(mutex, 0); 
			return -1;
		}

		in = leer_inodo(p_inodo);

		if(in.tipo == 2){
		
			int longitud = strlen(aux);
			aux[longitud-1] = '\0';
			printf("ERROR!!!! '%s' es un Fichero y no un Directorio!! Revisa bien la ruta \n", aux);

			senalizar_sem(mutex, 0); 
			return -1;
		}
	}


	p_inodo_dir = p_inodo = p_entrada = 0;

	//Si el archivo no existe (se busca con la función buscar entrada)
	if(buscar_entrada(camino, &p_inodo_dir, &p_inodo, &p_entrada) == -1){
	
		printf("Creando '%s' !!! \n", camino);	

		int tipo_camino = extraer_camino(camino, inicial, final);
	
		while((strcmp(final, "/") != 0) && (strcmp(final, "\0") != 0)){
			memset(inicial, '\0', 80);
			tipo_camino = extraer_camino(final, inicial, final);
		}


		int num_inodo;

		if((num_inodo = reservar_inodo(tipo_camino+1)) == -1){
			printf("No hay Inodos libres \n");	
		
			senalizar_sem(mutex, 0); 		
			return -1;
		}
		else{
			in = leer_inodo(num_inodo);
			in.tamano = 0;
			escribir_inodo(in, num_inodo);
		}

		strcpy(ent.nombre, inicial);
		ent.inodo = num_inodo;

		mi_write_f(p_inodo_dir, &ent, p_entrada * sizeof(entrada), sizeof(entrada));

		senalizar_sem(mutex, 0); 

		return 0;
		
	}
	else{
		printf("El fichero ya existe \n");	

		senalizar_sem(mutex, 0); 
		return -1;
	}

}

int mi_link(const char *camino1, const char *camino2){

}

int mi_unlink(const char *camino){

	unsigned int p_inodo_dir, p_inodo, p_entrada = 0;

	//Si no existe el fichero/directorio, notificamos un error.
	if(buscar_entrada(camino, &p_inodo_dir, &p_inodo, &p_entrada) == -1){
		printf("directorios.c -> mi_unlink => Error no existe el directorio a borrar\n");
		senalizar_sem(mutex, 0);
		return -1;
		
	} else if (strcmp(camino, "/") == 0){ 
		printf("directorios.c -> mi_unlink => Error no puedes borrar el directorio '/' \n");
		senalizar_sem(mutex, 0);
		return -1;
		
	} else {
	
	}


}

int mi_dir(const char *camino, char *buffer){

	unsigned int p_inodo, p_entrada, p_inodo_dir = 0;
	entrada entr;
	int bytesleidos = 0;
	char tamany[30]; // numero máximo de caracteres del dir
	
	memset(buffer,'\0', (tam_bloq * 6));
	
	if(buscar_entrada(camino, &p_inodo_dir, &p_inodo, &p_entrada) == -1){
		printf("directorios.c -> mi_dir => El directorio no existe\n");
		return -1;
	} else {
		
		inodo inod, inoaux;
		
		inod =leer_inodo(p_inodo);
		
		while (bytesleidos < inod.tamano){
			mi_read_f(p_inodo,&entr,bytesleidos,sizeof(entr));
			
			if (entr.inodo > 0){
			
				inoaux = leer_inodo(entr.inodo);
				if (inoaux.tipo !=0){
				
					if ((inoaux.tipo == 1) || (inoaux.tipo == 2)){
						strcat(buffer, "    ");
					}
					
					strcat(buffer,entr.nombre);
					
					if(inoaux.tipo == 1){
						strcat(buffer,"/[Dir]   ");
					}
					else if(inoaux.tipo == 2){
						strcat(buffer,"[Fichero]    ");
						memset(tamany, '\0', 30); 
						sprintf(tamany, "Tamaño = %d Bytes", inoaux.tamano);
						strcat(buffer, tamany);
					}
					
					strcat(buffer,":\n");
				}
				
				bytesleidos = bytesleidos + sizeof(entrada);
			} else {
				return 0;
			}
		
		}
	
	}
	
	//Devolvemos el número de ficheros que contiene el directorio
	return bytesleidos/sizeof(entrada);
}

int mi_stat(const char *camino, STAT *p_stat){

	esperar_sem(mutex, 0, 0);
	 
	unsigned int p_inodo, p_entrada, p_inodo_dir = 0;
	
	if (buscar_entrada(camino, &p_inodo_dir, &p_inodo, &p_entrada) == -1){
		printf("directorios.c -> mi_stat => Error al encontrar el directorio\n");
		senalizar_sem(mutex, 0);
		return -1;
	}else{
/*	
		inodo inod;
		if (leer_inodo(p_inodo) == -1){
			printf("directorios.c -> mi_stat => Error al leer el inodo %d \n", p_inodo);
			return -1;
		}
*/
		mi_stat_f(p_inodo, p_stat);
		
		senalizar_sem(mutex, 0);
		
		return 1;
	}
}


int mi_read(const char *camino, void *buf, unsigned int offset, unsigned int nbytes){

	unsigned int p_inodo, p_entrada, p_inodo_dir = 0;
	
	if (buscar_entrada(camino, &p_inodo_dir, &p_inodo, &p_entrada) == -1){
		printf("directorios.c -> mi_read => Error al encontrar el directorio\n");
		return -1;
	} else {
/*
		inodo inod;
		if (leer_inodo(p_inodo, &inod) == -1){
			printf("Error al leer el inodo %d \n", p_inodo);
			return -1;
		} 
*/
		mi_read_f(p_inodo, buf, offset, nbytes);
		return 1;
	}

}


int mi_write(const char *camino, const void *buf, unsigned int offset, unsigned int nbytes){

	esperar_sem(mutex, 0, 0);

	unsigned int p_inodo, p_entrada, p_inodo_dir = 0;
	
	if (buscar_entrada(camino, &p_inodo_dir, &p_inodo, &p_entrada) == -1){
		//printf("valor: %d\n", buscar_entrada(camino, &p_inodo_dir, &p_inodo, &p_entrada));
		printf("directorio.c -> mi_write => Error al encontrar el directorio\n");
		senalizar_sem(mutex, 0);
		return -1;
	} else {
/*
		inodo inod;
		if (leer_inodo(p_inodo, &inod) == -1){
			printf("Error al leer el inodo %d \n", p_inodo);
			return -1;
		}

*/
		int val =mi_write_f(p_inodo, buf, offset, nbytes);
		
		senalizar_sem(mutex, 0);
		
		return val;
	}
}



